package pub.cleangao.memm.spring;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;
import pub.cleangao.memm.annotation.RpcApi;
import pub.cleangao.memm.annotation.RpcService;
import pub.cleangao.memm.registry.RpcRuntime;
import pub.cleangao.memm.registry.RpcServiceConfig;
import pub.cleangao.memm.registry.RpcServiceRegistry;
import pub.cleangao.memm.transport.RequestTransport;
import pub.cleangao.memm.transport.RpcClientProxy;

import java.lang.reflect.Field;


@Slf4j
@Component
public class ExportLocalServices implements BeanPostProcessor {


    private final RpcServiceRegistry serviceRegistry;
    private final RequestTransport requestClient;

    public ExportLocalServices() {
        serviceRegistry = RpcRuntime.getRegistry();
        requestClient = RpcRuntime.getRequestClient();
    }

    @SneakyThrows
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (bean.getClass().isAnnotationPresent(RpcService.class)) {
            log.debug("discover rpc service implements: {}", bean.getClass().getCanonicalName());
            RpcService rpcService = bean.getClass().getAnnotation(RpcService.class);
            RpcServiceConfig rpcServiceConfig = new RpcServiceConfig();
            rpcServiceConfig.setGroup(rpcService.group());
            rpcServiceConfig.setVersion(rpcService.version());
            rpcServiceConfig.setFallback(rpcService.fallback());
            rpcServiceConfig.setServiceImpl(bean);
            if (rpcServiceConfig.getRpcServiceName() == null) {
                throw new RuntimeException("Rpc service :" + bean.getClass().getCanonicalName() + " has non-interface implemented.");
            }
            serviceRegistry.publishService(rpcServiceConfig);
            RpcRuntime.setFallbacks(rpcServiceConfig.getRpcServiceName(), rpcService.fallback());
        }
        return bean;
    }

    /**
     * 对标注了@RpcApi注解的字段动态生成代理对象
     * 从而实现远程服务的调用
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        Class<?> targetClass = bean.getClass();
        Field[] declaredFields = targetClass.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            RpcApi rpcReference = declaredField.getAnnotation(RpcApi.class);
            if (rpcReference != null) {
                RpcServiceConfig rpcServiceConfig = new RpcServiceConfig();
                rpcServiceConfig.setGroup(rpcReference.group());
                rpcServiceConfig.setVersion(rpcReference.version());
                rpcServiceConfig.setTimeout(rpcReference.timeout());
                // 创建代理对象
                RpcClientProxy rpcClientProxy = new RpcClientProxy(requestClient, rpcServiceConfig);
                Object clientProxy = rpcClientProxy.getProxy(declaredField.getType());
                declaredField.setAccessible(true);
                try {
                    declaredField.set(bean, clientProxy);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
        return bean;
    }


}
